package docker

import (
	"context"
	"io"
	"time"

	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/container"
	"github.com/docker/go-connections/nat"
)

// var DockerContainer = &dockerContainer{
// }

type dockerContainer struct {
}

func (receiver *dockerContainer) List() ([]types.Container, error) {
	cli, err := Docker.NewClient()
	if err != nil {
		return []types.Container{}, err
	}

	containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{})
	return containers, err
}
func (receiver *dockerContainer) Create(imageName, containerName string) (string, error) {
	port, err := nat.NewPort("tcp", "80")
	if err != nil {
		return "", err
	}

	exports := make(nat.PortSet, 10)
	exports[port] = struct{}{}

	config := &container.Config{
		Image:        imageName,
		ExposedPorts: exports,
		// Cmd: []string{"echo", "hello world"},
	}

	portBind := nat.PortBinding{HostPort: "80"}

	tmp := make([]nat.PortBinding, 0, 1)
	tmp = append(tmp, portBind)

	portMap := make(nat.PortMap, 0)
	portMap[port] = tmp

	hostConfig := &container.HostConfig{PortBindings: portMap}

	cli, err := Docker.NewClient()
	if err != nil {
		return "", err
	}
	body, err := cli.ContainerCreate(context.Background(), config, hostConfig, nil, nil, containerName)

	return body.ID, nil
}
func (receiver *dockerContainer) Remove(containerID string) (string, error) {
	cli, err := Docker.NewClient()
	if err != nil {
		return "", err
	}

	err = cli.ContainerRemove(context.Background(), containerID, types.ContainerRemoveOptions{})
	return containerID, err
}

func (receiver *dockerContainer) Start(containerID string) error {
	cli, err := Docker.NewClient()
	if err != nil {
		return err
	}

	err = cli.ContainerStart(context.Background(), containerID, types.ContainerStartOptions{})
	return err
}
func (receiver *dockerContainer) Stop(containerID string) error {
	cli, err := Docker.NewClient()
	if err != nil {
		return err
	}

	timeout := time.Second * 10
	err = cli.ContainerStop(context.Background(), containerID, &timeout)
	return err
}
func (receiver *dockerContainer) Restart(containerID string) error {
	cli, err := Docker.NewClient()
	if err != nil {
		return err
	}

	timeout := time.Second * 10
	err = cli.ContainerRestart(context.Background(), containerID, &timeout)
	return err
}
func (receiver *dockerContainer) Pause(containerID string) error {
	cli, err := Docker.NewClient()
	if err != nil {
		return err
	}

	err = cli.ContainerPause(context.Background(), containerID)
	return err
}
func (receiver *dockerContainer) Unpause(containerID string) error {
	cli, err := Docker.NewClient()
	if err != nil {
		return err
	}

	timeout := time.Second * 10
	err = cli.ContainerUnpause(context.Background(), containerID)
	return err
}

func (receiver *dockerContainer) Wait(containerID string) error {
	cli, err := Docker.NewClient()
	if err != nil {
		return err
	}

	statusCh, errCh := cli.ContainerWait(context.Background(), containerID, container.WaitConditionNotRunning)
	select {
	case err := <-errCh:
		if err != nil {
			return err
		}
	case <-statusCh:
	}

	return nil
}

func (receiver *dockerContainer) Inspect(containerID string) (types.ContainerJSON, error) {
	cli, err := Docker.NewClient()
	if err != nil {
		return types.ContainerJSON{}, err
	}

	out, err := cli.ContainerInspect(context.Background(), containerID)
	return out, err
}
func (receiver *dockerContainer) InspectWithRaw(containerID string) (types.ContainerJSON, []byte, error) {
	cli, err := Docker.NewClient()
	if err != nil {
		return types.ContainerJSON{}, []byte{}, err
	}

	out, data, err := cli.ContainerInspectWithRaw(context.Background(), containerID, true)
	return out, data, err
}
func (receiver *dockerContainer) Logs(containerID string) (io.ReadCloser, error) {
	cli, err := Docker.NewClient()
	if err != nil {
		return nil, err
	}

	out, err := cli.ContainerLogs(context.Background(), containerID, types.ContainerLogsOptions{ShowStdout: true})
	return out, err
}
